home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Telnet / NCSA / tn3270 2.4d7 source / NCSA⁄BYU TCP⁄IP / ip.c < prev    next >
Text File  |  1991-06-27  |  13KB  |  531 lines

  1. /*
  2. *   IP.C
  3. *   IP level routines, including ICMP
  4. *   also includes a basic version of UDP, not generalized yet
  5. *
  6. ****************************************************************************
  7. *                                                                          *
  8. *      part of:                                                            *
  9. *      TCP/IP kernel for NCSA Telnet                                       *
  10. *      by Tim Krauskopf                                                    *
  11. *                                                                          *
  12. *      National Center for Supercomputing Applications                     *
  13. *      152 Computing Applications Building                                 *
  14. *      605 E. Springfield Ave.                                             *
  15. *      Champaign, IL  61820                                                *
  16. *                                                                          *
  17. *    Copyright (c) 1987, Board of Trustees of the University of Illinois   *
  18. *                                                                          *
  19. ****************************************************************************
  20. *  Revision history:
  21. *
  22. *  10/87  Initial source release, Tim Krauskopf
  23. *  2/88  typedefs of integer lengths, TK
  24. */
  25.  
  26. #include <stdio.h>
  27. #include <String.h>
  28. #include "protocol.h"
  29. #include "data.h"
  30. #include "tools.h"
  31. #include "mactools.h"
  32. #include "tcp.h"
  33.  
  34. extern uint16 ipcheck
  35.   (
  36.     void *buf,
  37.     int wdcnt
  38.   );
  39.  
  40. extern uint16 tcpcheck
  41.   (
  42.     void *phd,
  43.     void *buf,
  44.     int btcnt
  45.   );
  46.  
  47. /****************************************************************************/
  48. /*  udpinterpret
  49. *   take incoming UDP packets and make them available to the user level
  50. *   routines.  Currently keeps the last packet coming in to a port.
  51. *
  52. *   Limitations:
  53. *   Can only listen to one UDP port at a time.  Only saves the last packet
  54. *   received on that port.
  55. *   Port numbers should be assigned like TCP ports are (future).
  56. */
  57. int udpinterpret
  58.   (
  59.     UDPKT *p,
  60.     int ulen
  61.   )
  62.     {
  63.     uint hischeck,mycheck;
  64. /*
  65. *  did we want this data ?  If not, then let it go, no comment
  66. *  If we want it, copy the relevent information into our structure
  67. */
  68.     if (intswap(p->u.dest) != ulist.listen) 
  69.         return(1);
  70.  
  71. /*
  72. *  first compute the checksum to see if it is a valid packet
  73. */
  74.     hischeck = p->u.check;
  75.     p->u.check = 0;
  76.  
  77.     if (hischeck) {
  78.         movebytes(tcps.source,p->i.ipsource,8);
  79.         tcps.z = 0;
  80.         tcps.proto = p->i.protocol;
  81.  
  82.         tcps.tcplen = intswap(ulen);
  83.  
  84.  
  85.         mycheck = tcpcheck(&tcps,&p->u,ulen);
  86.  
  87.         if (hischeck != mycheck) {
  88.             netposterr(700);
  89.             return(2);
  90.         }
  91.  
  92.         p->u.check = hischeck;                    /* put it back */
  93.     }
  94.  
  95.     ulen -= 8;                        /* account for header */
  96.     if (ulen > UMAXLEN)                /* most data that we can accept */
  97.         ulen = UMAXLEN;
  98.  
  99.     movebytes(ulist.who,p->i.ipsource,4);
  100.     movebytes(ulist.data,p->data,ulen);
  101.     ulist.length = ulen;
  102.     ulist.stale = 0;
  103.     netputuev(USERCLASS,UDPDATA,ulist.listen);        /* post that it is here */
  104.  
  105.     return(0);
  106. } /* udpinterpret */
  107.  
  108. /***************************************************************************/
  109. /*  neticmpturn
  110. *
  111. *   send out an icmp packet, probably in response to a ping operation
  112. *   interchanges the source and destination addresses of the packet,
  113. *   puts in my addresses for the source and sends it
  114. *
  115. *   does not change any of the ICMP fields, just the IP and dlayers
  116. *   returns 0 on okay send, nonzero on error
  117. */
  118.  
  119. int neticmpturn
  120.   (
  121.     ICMPKT *p,
  122.     int ilen
  123.   )
  124.     {
  125.     unsigned char *pc;
  126. /*
  127. *  reverse the addresses, dlayer and IP layer
  128. */
  129.     if (comparen(p->d.me,broadaddr,DADDLEN))
  130.         return(0);
  131.  
  132.     movebytes(p->d.dest,p->d.me,DADDLEN);
  133.  
  134. #ifdef MAC
  135. /*
  136. *   look up address in the arp cache if we are using AppleTalk
  137. *   encapsulation.
  138. */
  139.     if (!nnemac) {
  140.         pc = getdlayer(p->i.ipsource);
  141.         if (pc != NULL)
  142.             movebytes(p->d.dest,pc,DADDLEN);
  143.         else
  144.             return(0);        /* no hope this time */
  145.     }
  146. #endif
  147.  
  148.  
  149.     movebytes(p->i.ipdest,p->i.ipsource,4);
  150.     movebytes(p->d.me,nnmyaddr,DADDLEN);
  151.     movebytes(p->i.ipsource,nnipnum,4);
  152. /*
  153. *  prepare ICMP checksum
  154. */
  155.     p->c.check = 0;
  156.     p->c.check = ipcheck(&p->c,ilen>>1);
  157.  
  158. /*
  159. *   iplayer for send
  160. */
  161.     p->i.ident = intswap(nnipident++);
  162.     p->i.check = 0;
  163.     p->i.check = ipcheck(&p->i,10);
  164.  
  165. /*
  166. *  send it
  167. */
  168.     return(dlayersend(p,sizeof(DLAYER)+sizeof(IPLAYER)+ilen));
  169.  
  170. } /* neticmpturn */
  171.  
  172. /****************************************************************************/
  173. /*  icmpinterpret
  174. *   interpret the icmp message that just came in
  175. */
  176. int icmpinterpret
  177.   (
  178.     ICMPKT *p,
  179.     int icmplen
  180.   )
  181.     {
  182.     uint i,hisck;
  183.     IPLAYER *iptr;
  184.  
  185.     i = p->c.type;
  186.     netposterr(600 + i);        /* provide info for higher layer user */
  187.  
  188. #ifdef oldway
  189.     hisck = p->c.check;
  190.     p->c.check = 0;
  191. #else
  192. #pragma unused(hisck)
  193. #endif
  194.  
  195.     if (p->c.check) {            /* ignore if chksum = 0 */
  196.         if (ipcheck(&p->c,icmplen>>1)) {
  197.             netposterr(699);
  198.             return(-1);
  199.         }
  200.     }
  201.  
  202.     switch (i) {
  203.         case 8:                            /* ping request sent to me */
  204.             p->c.type = 0;                /* echo reply type */
  205.             neticmpturn(p,icmplen);        /* send back */
  206.             break;
  207.  
  208.         case 5:                            /* ICMP redirect */
  209.             iptr = (IPLAYER *)p->data;
  210.             netputuev(ICMPCLASS,IREDIR,0);        /* event to be picked up */
  211.  
  212.             movebytes(nnicmpsave,iptr->ipdest,4);        /* dest address */
  213.             movebytes(nnicmpnew,&p->c.part1,4);            /* new gateway */
  214.             break;
  215.  
  216.         default:
  217.             break;
  218.     }
  219.  
  220.     return(0);
  221. } /* icmpinterpret */
  222.  
  223. /***************************************************************************/
  224. /*  ipinterpret
  225. *   Called by the reception routine with a new IP packet.  Check the checksum,
  226. *   addressing and protocol type and call appropriate routines.
  227. */
  228.  
  229. int ipinterpret
  230.   (
  231.     IPKT *p
  232.   )
  233.     {
  234.     int iplen,i;
  235.  
  236. /*
  237. *  We cannot handle fragmented IP packets yet, return an error
  238. */
  239.     if (p->i.frags & 0x20) {
  240.         netposterr(304);
  241.         return(1);
  242.     }
  243.  
  244. /*
  245. *  checksum verification of IP header
  246. */
  247.  
  248.     if (p->i.check) {             /* no IP checksumming if check=0 */
  249.         if (ipcheck(&p->i.versionandhdrlen,(p->i.versionandhdrlen & 0x0f) << 1))  {
  250.             netposterr(300);    /* bad IP checksum */
  251.             return(1);             /* drop packet */
  252.         }
  253.     }
  254.  
  255. /*
  256. *  check to make sure that the packet is for me.
  257. *  Throws out all packets which are not directed to my IP address.
  258. *
  259. *  This code is incomplete.  It does not pass broadcast IP addresses up
  260. *  to higher layers.  It used to report packets which were incorrectly
  261. *  addressed, but no longer does.  Needs proper check for broadcast 
  262. *  addresses.
  263. */
  264.     if (!comparen(nnipnum,p->i.ipdest,4)) {     /* potential non-match */
  265.         return(1);                /* drop packet */
  266.     }
  267. /*
  268. *  Extract total length of packet
  269. */
  270.     iplen = intswap(p->i.tlen);
  271.  
  272. /*
  273. *  See if there are any IP options to be handled.
  274. *  We don't understand IP options, post a warning to the user and drop
  275. *  the packet.
  276. */
  277.     i = (p->i.versionandhdrlen & 0x0f)<<2;
  278.  
  279.     if (i > 20) {
  280.         netposterr(302);                /* packet with options */
  281.         return(1);
  282.     }
  283.  
  284.     switch (p->i.protocol) {        /* which protocol to handle this packet? */
  285.         case PROTUDP:
  286.             return(udpinterpret((UDPKT *) p,iplen-i));
  287.         case PROTTCP:
  288.             return(tcpinterpret((TCPKT *) p,iplen-i));    /* pass tcplen on to TCP */
  289.         case PROTICMP:
  290.             return(icmpinterpret((ICMPKT *) p,iplen-i));
  291.         default:
  292.             netposterr(303);
  293.             return(1);
  294.     }
  295.  
  296.     return(0);
  297. } /* ipinterpret */
  298.  
  299. #ifdef NNDEBUG
  300. ipdump(p)
  301.     IPKT *p;
  302.     {
  303.     uint16 iplen,iid;
  304.  
  305.     iid = intswap(p->i.ident);
  306.  
  307.     iplen = intswap(p->i.tlen);
  308.  
  309.     puts("found IP packet:");
  310.  
  311.     printf("Version+hdr: %x     service %d      tlen %u   \n",
  312.             p->i.versionandhdrlen,p->i.service,iplen);
  313.     printf("Ident: %u    frags: %4x    ttl: %d    prot: %d  \n",
  314.             iid,p->i.frags,p->i.ttl,p->i.protocol);
  315.     printf("addresses: s: %d.%d.%d.%d    t: %d.%d.%d.%d \n",
  316.         p->i.ipsource[0],p->i.ipsource[1],p->i.ipsource[2],p->i.ipsource[3],
  317.         p->i.ipdest[0],p->i.ipdest[1],p->i.ipdest[2],p->i.ipdest[3]);
  318.  
  319.  
  320.     puts("\n");
  321.     
  322. }
  323.  
  324. /***************************************************************************/
  325. /*  ipsend   THIS ROUTINE HAS NOT BEEN TESTED, NEVER USED!
  326. *   generic send of an IP packet according to parameters.  Use of this
  327. *   procedure is discouraged.  Terribly inefficient, but may be useful for
  328. *   tricky or diagnostic situations.  Unused for TCP.
  329. *
  330. *   usage:  ipsend(data,ident,prot,options,hdrlen)
  331. *        data is a pointer to the data to be sent
  332. *       ident is the 16 bit identifier
  333. *       prot is the protocol type, PROTUDP or PROTTCP or other
  334. *       hlen is in bytes, total header length, 20 is minimum
  335. *       dlen is the length of the data field, in bytes
  336. *        who is ip address of recipient
  337. *       options must be included in hlen and hidden in the data stream
  338. */
  339. ipsend(data,dlen,iid,iprot,who,hlen)
  340.     unsigned char *data,iprot,*who;
  341.     int iid,dlen,hlen;
  342.     {
  343.     int iplen;
  344.  
  345.     if (dlen > 512)
  346.         dlen = 512;
  347.  
  348.     iplen = hlen+dlen;                         /* total length of packet */
  349.     blankip.i.tlen = intswap(iplen);            /* byte swap */
  350.  
  351.     blankip.i.versionandhdrlen = 0x40 | (hlen>>2);
  352.  
  353.     blankip.i.ident = intswap(iid);           /* byte swap */
  354.  
  355.     blankip.i.protocol = iprot;
  356.  
  357.     blankip.i.check = 0;                    /* set to 0 before calculating */
  358.  
  359.     movebytes(blankip.i.ipdest,who,4);
  360.     movebytes(blankip.d.me,myaddr,DADDLEN);
  361.  
  362.     movenbytes(blankip.x.data,data,dlen);  /* might be header options data */
  363.  
  364.     blankip.i.check = ipcheck(&blankip.i.versionandhdrlen,hlen>>1);
  365.                                         /* checks based on words */
  366.  
  367.  
  368. /* resolve knowledge of Ethernet hardware addresses */
  369.  
  370. /*
  371. *  This is commented out because I know that this procedure is broken!
  372. *  If you use it, debug it first.
  373.  
  374.     dlayersend(&blankip,iplen+14);
  375. */
  376.  
  377.     return(0);
  378. } /* ipsend */
  379.  
  380. #endif
  381.  
  382. /****************************************************************************/
  383. /*  neturead
  384. *   get the data from the UDP buffer
  385. *   Returns the number of bytes transferred into your buffer, -1 if none here
  386. *   This needs work.
  387. */
  388. int neturead
  389.   (
  390.     char *buffer
  391.   )
  392.     {
  393.     if (ulist.stale)
  394.         return(-1);
  395.  
  396.     movebytes(buffer,ulist.data,ulist.length);
  397.     ulist.stale = 1;
  398.  
  399.     return(ulist.length);
  400. } /* neturead */
  401.  
  402. /***************************************************************************/
  403. /*  netulisten
  404. *   Specify which UDP port number to listen to.
  405. *   Can only listen to one at a time.
  406. */
  407. void netulisten
  408.   (
  409.     int port
  410.   )
  411.     {
  412.     ulist.listen = port;
  413. }
  414.  
  415. /***************************************************************************/
  416. /*  netusend
  417. *   send some data out in a UDP packet
  418. *   uses the preinitialized data in the port packet ulist.udpout
  419. *   
  420. *   returns 0 on okay send, nonzero on error
  421. */
  422. int netusend
  423.   (
  424.     unsigned char *machine,
  425.     unsigned int port,
  426.     unsigned int retport,
  427.     unsigned char *buffer,
  428.     int n
  429.   )
  430.     {
  431.     unsigned char *pc;
  432.  
  433.     if (n > UMAXLEN)
  434.         n = UMAXLEN;
  435. /*
  436. *  make sure that we have the right dlayer address
  437. */
  438.     if (!comparen(machine,ulist.udpout.i.ipdest,4)) {
  439.         pc = netdlayer(machine);
  440.         if (pc == NULL) 
  441.             return(-2);
  442.         movebytes(ulist.udpout.d.dest,pc,DADDLEN);
  443.         movebytes(ulist.udpout.i.ipdest,machine,4);
  444.         movebytes(ulist.tcps.dest,machine,4);
  445.     }
  446.  
  447.     ulist.udpout.u.dest = intswap(port);
  448.     ulist.udpout.u.source = intswap(retport);
  449.     ulist.tcps.tcplen = ulist.udpout.u.length = intswap(n+sizeof(UDPLAYER));
  450.     movenbytes(ulist.udpout.data,buffer,n);
  451.  
  452. /*
  453. *  put in checksum
  454. */
  455.     ulist.udpout.u.check = 0;
  456.     ulist.udpout.u.check = tcpcheck(&ulist.tcps,&ulist.udpout.u,n+sizeof(UDPLAYER));
  457.  
  458. /*
  459. *   iplayer for send
  460. */
  461.     ulist.udpout.i.tlen = intswap(n+sizeof(IPLAYER)+sizeof(UDPLAYER));
  462.     ulist.udpout.i.ident = intswap(nnipident++);
  463.     ulist.udpout.i.check = 0;
  464.     ulist.udpout.i.check = ipcheck(&ulist.udpout.i,10);
  465. /*
  466. *  send it
  467. */
  468.     return(dlayersend(&ulist.udpout,
  469.         sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(UDPLAYER)+n));
  470. } /* netusend */
  471.  
  472. #ifdef notneeded
  473. /***************************************************************************/
  474. /*  neticmpsend
  475. *   Not currently used.  Has not been tested since 9/87.
  476. *   Do not assume this works (TK)
  477. *
  478. *   send out an icmp packet, probably to do a ping operation
  479. *   
  480. *   returns 0 on okay send, nonzero on error
  481. */
  482. neticmpsend(machine,type,code,buffer,n)
  483.     unsigned char *machine,*buffer,type,code;
  484.     int n;
  485.     {
  486.     unsigned char *pc;
  487.  
  488.     if (n > ICMPMAX)
  489.         n = ICMPMAX;
  490. /*
  491. *  make sure that we have the right dlayer address
  492. *
  493. *  this may be re-entrant, needs checking.  Okay, as long as this compare
  494. *  is false when called from netsleep() routines!
  495. *  When called from user routines, we are okay.
  496. */
  497.     if (!comparen(machine,blankicmp.i.ipdest,4)) {
  498.         pc = netdlayer(machine);
  499.         if (pc == NULL) 
  500.             return(-2);
  501.         movebytes(blankicmp.d.dest,pc,DADDLEN);
  502.         movebytes(blankicmp.i.ipdest,machine,4);
  503. /*        movebytes(ulist.tcps.dest,machine,4); */
  504.     }
  505. /*
  506. *  prepare ICMP portion
  507. */
  508.     blankicmp.c.type = type;
  509.     blankicmp.c.code = code;
  510.     movenbytes(&blankicmp.data,buffer,n);
  511.  
  512.     blankicmp.c.check = 0;
  513.     blankicmp.c.check = ipcheck(&blankicmp.c,(sizeof(ICMPLAYER)+n)>>1);
  514.  
  515. /*
  516. *   iplayer for send
  517. */
  518.     blankicmp.i.tlen = intswap(n+sizeof(IPLAYER)+sizeof(ICMPLAYER));
  519.     blankicmp.i.ident = intswap(nnipident++);
  520.     blankicmp.i.check = 0;
  521.     blankicmp.i.check = ipcheck(&blankicmp.i,10);
  522. /*
  523. *  send it
  524. */
  525.     return(dlayersend(&blankicmp,
  526.         sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(ICMPLAYER)+n));
  527.  
  528. }
  529. #endif
  530.